/**
 ******************************************************************************
 * @file	env.c
 * @brief	环境变量字符串操作

 每个环境变量以 \0 结尾，所有环境变量以 \0\0 结尾
 默认环境变量为 ENV_DEF 其大小是 ENV_SIZE，

- 2017-6-23,MenglongWu,MenglongWoo@aliyun.com
 *
 Copyright (C) 2017 桂林聚联科技有限公司, Inc. All Rights Reserved.
*/
#include <stdio.h>
#include <string.h>
#include "env.h"


extern double _atof(char *s);


// char flash[ENV_SIZE] = {
// 	"sn=0123456789\0"

// 	"ch1_10_adc=351\0ch1_10_dac=601\0"
// 	"ch2_10_adc=352\0ch2_10_dac=602\0"
// 	"ch3_10_adc=353\0ch3_10_dac=603\0"

// 	"lv1_low=127\0lv1_high=1950\0"
// 	"lv2_low=127\0lv2_high=1950\0"
// 	"lv3_low=126\0lv3_high=1302\0"
// 	"lv4_low=129\0lv4_high=1277\0"
// 	"lv5_low=100\0lv5_high=1320\0"
// 	"lv6_low=206\0lv6_high=1023\0"
// 	"lv7_low=213\0lv7_high=2136\0"

// 	"ch1_wave=1310\0"
// 	"ch2_wave=1550\0"
// 	"ch3_wave=1490\0"

// 	"ch1_en=1\0"
// 	"ch2_en=1\0"
// 	"ch3_en=1\0"
// 	"_1550_ref_1310=1.0155\0"
// 	"_1490_ref_1310=1.0490\0"
// 	"_1625_ref_1310=1.0625\0"
// 	"_850_ref_1310=1.085\0"
// 	"\0"
// };
struct sys_env g_sys_env = {
	33,
	{
		// "sn=0123456789\0"
		// "ch1_10_adc=300\0"
		// "ch1_10_dac=350\0"
		// "ch2_10_adc=300\0"
		// "ch2_10_dac=350\0"
		// "ch3_10_adc=300\0"
		// "ch3_10_dac=350\0"
		// "ch1_5_adc=950\0"
		// "ch1_5_dac=1106\0"
		// "ch2_5_adc=950\0"
		// "ch2_5_dac=1106\0"
		// "ch3_5_adc=950\0"
		// "ch3_5_dac=1106\0"
		// "ch1_en=1\0"
		// "ch2_en=1\0"
		// "ch3_en=1\0"
		// "go_wave=1490\0"
		// "ch1_wave=1310\0"
		// "ch2_wave=1550\0"
		"\0"
		"\0"
	},
};
// char *g_env = flash;


unsigned int ap_hash(unsigned char *data, unsigned int len)
{
	long hash = 0xaaaaaaaa;
	int i;
	for (i = 0; i < len; i++) {
		if((i & 1) == 0) {
			hash ^= ((hash << 7) ^ data[i] ^ (hash >> 3));
		} else {
			hash ^= (~((hash << 11) ^ data[i] ^ (hash >> 5)));
		}
	}
	return hash;
}



void do_printenv()
{
	char *penv;
	int   index = 0;

	penv = g_sys_env.env;
	while((penv - g_sys_env.env) < ENV_SIZE - 2) {
		if (*penv == '\0' && *(penv + 1) == '\0') {
			break;
		}
		if (*penv == '\0') {
			penv++;
			printf("%s\r\n", penv);
		}
		penv++;
	}
}

char *_do_getenv(char *find)
{
	char *penv;
	int len, eq_offset;

	eq_offset = strlen(find);
	penv      = g_sys_env.env;

	while((penv - g_sys_env.env) < ENV_SIZE - 2) {
		if (*penv == '\0' && *(penv + 1) == '\0') {
			break;
		}
		if (*penv != '\0') {
			len = strlen(penv);
			if (0 == strncmp(penv, find, eq_offset) &&
			    '=' == *(penv + eq_offset) ) {
				return penv + eq_offset + 1;
			}
			penv = penv + len;
		}
		penv++;
	}
	return NULL;
}

int total_env_len(char *in_env)
{
	char *penv, *pstart;

	penv   = in_env;
	pstart = in_env;

	// 在字符串里查找两个连续的\0作为结束符
	while((penv - pstart) < ENV_SIZE - 2) {
		if (*penv == '\0' && *(penv + 1) == '\0') {
			break;
		}
		penv++;
	}

	return penv - pstart + 2;
}
int add_env(char *name, char *val)
{
	// TODO 添加不存在的环境变量
	if (0) {  // 字符串长度超过 ENV_SIZE
		return -1;
	}
	// 正常插入
	return 0;
}
int edit_env(char *name, char *val)
{
	int len_old, len_new;
	int total_len, move_len;
	char *env;
	char *from, *to;

	env     = _do_getenv(name);
	len_old = strlen(env);
	len_new = strlen(val);

	/*g_sys_env.env ......xxx=12345\0....\0\0
	*/
	total_len = total_env_len(g_sys_env.env);
	if (len_new > len_old) {
		move_len = total_len - (env - g_sys_env.env) - len_old;
		from     = g_sys_env.env + total_len;
		to       = from + (len_new - len_old);
		while(move_len) {
			*to = *from;
			from--;
			to--;
			move_len--;
		}

	} else if (len_new < len_old) {
		move_len = total_len - (env - g_sys_env.env) - len_old;
		from     = env + len_old;
		to       = env + len_new;

		while(move_len) {
			*to = *from;
			from++;
			to++;
			move_len--;
		}
	} else if (len_new == len_old) {
		// do nothing
	}
	// TODO 考虑如何使用 strncpy 代替
	strcpy(env, val);
	return 0;
}

void _do_setenv(char *name, char *val)
{
	char *env;

	env = _do_getenv(name);
	if (env == NULL) {
		add_env(name, val);
	} else {
		edit_env(name, val);
	}
}

void calc_hash()
{
	int len = total_env_len(g_sys_env.env);

	g_sys_env.hash = ap_hash(g_sys_env.env, len);
}
int isvalid_env()
{
	int len = total_env_len(g_sys_env.env);
	unsigned int hash = ap_hash(g_sys_env.env, len);

#if 1 || CONFIG_ENV_DBG
	int len_def = total_env_len(ENV_DEF);

	// 实际上只要 ENV_DEF 符合末尾 \0\0，返回值就不会 > ENV_SIZE
	if (len_def >= ENV_SIZE) {
		printf("default env maybe too large: ENV_SIZE %d  ENV_DEF len %d\r\n",
			ENV_SIZE, len_def);
	}

	printf("%s():"
	       "env len: %d  "
	       "righ  hash: %x  "
	       "store hash: %x\r\n", __FUNCTION__,
	       len ,
	       hash,
	       g_sys_env.hash);


#endif
	if (g_sys_env.hash == hash) {
		return 0;
	} else {
		return -1;
	}
}

int copy_def_env()
{
	int len_def = total_env_len(ENV_DEF);
	if (len_def >= ENV_SIZE) {
		len_def = ENV_SIZE;
		printf("default env maybe too large: ENV_SIZE %d  ENV_DEF len %d\r\n",
			ENV_SIZE, len_def);
	}
	memcpy(g_sys_env.env, ENV_DEF, len_def);
}
int test_env()
// int main()
{
	char *env;

	// memcpy(g_sys_env.env, flash, ENV_SIZE);
	// isvalid_env();

	// env = _do_getenv("go_wave");

	// printf("env : %s\r\n", env);
	env = _do_getenv("sn");

	env = _do_getenv("ch1_wave");
	_do_setenv("ch1_wave", "1");
	env = _do_getenv("ch2_wave");
	_do_setenv("ch2_wave", "1");
	env = _do_getenv("ch3_wave");
	_do_setenv("ch3_wave", "1");
	do_printenv();

	env = _do_getenv("ch1_wave");
	_do_setenv("ch1_wave", "1000");
	env = _do_getenv("ch2_wave");
	_do_setenv("ch2_wave", "2000");
	env = _do_getenv("ch3_wave");
	_do_setenv("ch3_wave", "3000");
	do_printenv();

	calc_hash();
	return 0;
}

double _atof(char *s)
{
	double v = 0, k = 0, j = 1;
	int sign = 1;

	while (*s == ' '  ||  (unsigned int)(*s - 9) < 5u) {
		s++;
	}
	switch (*s) {
	case '-':
		sign = -1;
	case '+':
		++s;
	}
	while ((unsigned int) (*s - '0') < 10u) {
		v = v * 10 + *s - '0';
		++s;
	}
	if(*s == '.') {
		s++;
		while ((unsigned int) (*s - '0') < 10u) {
			k = k * 10 + *s - '0';
			++s;
			j = j * 10;
		}
		k /= j;
	}

	v = v + k;
	return sign == -1 ? -v : v;
}


int envtostr(void *output, char *env, void *ptr)
{
	char *out = (char *)output;
	char *val;
	int *len = (int *)ptr;

	*out = NULL;
	val = _do_getenv(env);

	if (val) {
		strncpy(out, val, *len);
		out[*len] = '\0';
	}
	return 0;
}

int envtoi(void *output, char *env, void *ptr)
{
	int *out = (int *)output;
	char *val;

	*out = 0;
	val = _do_getenv(env);

	if (val) {
		printf("val %s\r\n", val);
		*out = atoi(val);
	}
	return 0;
}
int envtos(void *output, char *env, void *ptr)
{
	short *out = (short *)output;
	char *val;

	*out = 0;
	val = _do_getenv(env);
	if (val) {
		*out = (short)atoi(val);
	}
	return 0;
}

int envtof(void *output, char *env, void *ptr)
{
	float *out = (float *)output;
	char *val;

	*out = 0;
	val = _do_getenv(env);

	if (val) {
		*out = _atof(val);
	}
	return 0;
}


/*
struct control_p {
	int in_deta;	// 输入探测偏差值
	int out_ctrl;	// 输出控制值
	int next_time;  // 控制间隔ms
};


struct control_p g_p[] = {
	{ 50, -100, 1},
	{ 30, -20, 2},
	{ 20, -10, 3},
	{ 2,  -4, 4},
};

int Control_P(
	struct control_p *rule,
	int rule_size,
	int in_target,
	int in_current)
{
	int i;
	int deta = in_current - in_target;

	for (i = 0; i < rule_size; i++) {
#if 0
		if (rule[i].in_deta > 0) {
			if (deta > rule[i].in_deta) {
				return rule[i].out_ctrl;
			} else if (-deta > rule[i].in_deta) {
				return -rule[i].out_ctrl;
			}
		} else {
			if (deta < rule[i].in_deta) {
				return -rule[i].out_ctrl;
			} else if (-deta < rule[i].in_deta) {
				return rule[i].out_ctrl;
			}
		}
#else // in_deta 全是正数
		if (deta > rule[i].in_deta) {
			return rule[i].out_ctrl;
		} else if (-deta > rule[i].in_deta) {
			return -rule[i].out_ctrl;
		}
#endif
	}
}

struct in {
	int in_target;
	int in_current;
};
int main()
{
	struct in list[] = {
		{0, 51},
		{0, -51},
		{0, 31},
		{0, -31},
		{0, 20},
		{0, -20},
	};
	int out;
	for (int i = 0; i < sizeof(list) / sizeof(struct in); i++) {
		out = Control_P(
				  g_p,
				  sizeof(g_p) / sizeof(struct control_p),
				  list[i].in_target, list[i].in_current);

		printf("t %d c %d %d\r\n",
			   list[i].in_target, list[i].in_current,
			   out);
	}
	return 0;
}*/

void env_2_system(struct load_env *sys_vals, int count)
{
	int i;

	for (i = 0; i < count; i++) {
		sys_vals[i].fun(sys_vals[i].output, sys_vals[i].env, sys_vals[i].ptr);

		// #if 1 || CONFIG_PRINT_SYS_PARAM
#if 0
		switch (sys_vals[i].type) {
		case ENV_T_SHORT: {
			short *out = sys_vals[i].output;
			printf("%s : %d\r\n", sys_vals[i].env, *out);
			break;
		}
		case ENV_T_INT: {
			int *out = sys_vals[i].output;
			printf("%s : %d\r\n", sys_vals[i].env, *out);
			break;
		}
		case ENV_T_STR: {
			char *out = sys_vals[i].output;
			printf("%s : %s\r\n", sys_vals[i].env, out);
			break;
		}
		case ENV_T_FLOAT: {
			float *out = sys_vals[i].output;
			printf("%s : %f\r\n", sys_vals[i].env, *out);
			break;
		}
		default:
			break;
		}
#endif
	}
}
